package com.songcan.gateway.configuration;

import com.songcan.gateway.route.service.CustomRouteDefinitionService;
import com.songcan.gateway.vo.CustomRouteDefinitionVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.InMemoryRouteDefinitionRepository;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.cloud.gateway.support.NotFoundException;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import static java.util.Collections.synchronizedMap;

/**
 * 动态路由，存在无法刷新内存问题 后期处理
 */
public class CustomRouteDefinitionLoad extends InMemoryRouteDefinitionRepository  {

    @Autowired
    private CustomRouteDefinitionService customRouteDefinitionService;


    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        try {
            Map<String, RouteDefinition> routes = synchronizedMap(
                    new LinkedHashMap<String, RouteDefinition>());
            Map<String,CustomRouteDefinitionVO> customRouteDefinitions = customRouteDefinitionService.findAll();
            for (String s : customRouteDefinitions.keySet()) {

                 CustomRouteDefinitionVO customRouteDefinitionVO = customRouteDefinitions.get(s);
                RouteDefinition definition = new RouteDefinition();
                definition.setId(customRouteDefinitionVO.getId());
                definition.setUri(new URI(customRouteDefinitionVO.getUri()));
                List<PredicateDefinition> predicateDefinitions = customRouteDefinitionVO.getPredicates();
                if (predicateDefinitions != null) {
                    definition.setPredicates(predicateDefinitions);
                }
                List<FilterDefinition> filterDefinitions = customRouteDefinitionVO.getFilters();
                if(filterDefinitions != null){
                    definition.setFilters(filterDefinitions);
                }
                routes.put(definition.getId(),definition);
            }
            return Flux.fromIterable(routes.values());
        } catch (Exception e) {
            e.printStackTrace();
            return Flux.empty();
        }
    }

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        return route.flatMap(r -> {
            try {
                RouteDefinition definition = new RouteDefinition();
                CustomRouteDefinitionVO customRouteDefinition = new CustomRouteDefinitionVO();
                customRouteDefinition.setId(r.getId());
                customRouteDefinition.setUri(r.getUri().toString());
                customRouteDefinition.setPredicates(r.getPredicates());
                customRouteDefinition.setFilters(r.getFilters());
                customRouteDefinitionService.save(customRouteDefinition);

                return Mono.empty();
            } catch (Exception e) {
                e.printStackTrace();
                return Mono.defer(() -> Mono.error(new NotFoundException("RouteDefinition save error: "+ r.getId())));
            }
        });
    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        return routeId.flatMap(id -> {
            try {
                customRouteDefinitionService.deleteById(id);
                return Mono.empty();
            } catch (Exception e) {
                e.printStackTrace();
                return Mono.defer(() -> Mono.error(new NotFoundException("RouteDefinition delete error: " + routeId)));
            }
        });
    }
}
